/*
 ============================================================================
 Name        : usrSimpleApp.c
 Author      :
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <error.h>
#include <malloc.h>
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdint.h>
#include <string.h>
#include <time.h>

#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include "reg_rw.h"
#include "dma_from_device.h"
#include "pspHead.h"

extern unsigned long long g_word;

extern void *
xdmaMemAllocBuf(unsigned int BufIndex, unsigned int align, unsigned int nBytes);

#define RIO_RECV_LEVEL (1024)
inputmsg g_netRecvUsrInfo[RIO_RECV_LEVEL];
u32 gxRecvUsrInfoWptr = 0;
u32 gxRecvUsrInfoRptr = 0;
u32 gxRecvUsrInfoTotal = 0;

sem_t xdmaSemInput;

int run_xdma_flag;

int xdma_fiberLength[6];
int xdma_k_count[12];
int xdma_fpga_version;
int xdma_tongbu;

void sync_bslWaitInputData() {
	sem_wait(&xdmaSemInput);
}

int sync_bslGetInputData(void* msg) {
	struct InputInfoMsg *pInfoMsg = (struct InputInfoMsg *) msg;
	unsigned int wptr;
	unsigned int rptr;
	int i = 0;
	int flag = 0;
	rptr = gxRecvUsrInfoRptr;
	wptr = gxRecvUsrInfoWptr;

	if (rptr != wptr) {
		pInfoMsg->pipeNum = g_netRecvUsrInfo[rptr].pipeNum;
		flag = g_netRecvUsrInfo[rptr].flag;
		if (flag == 0) {
			pInfoMsg->flag = 0;
			for (i = 0; i < 6; i++) {
				pInfoMsg->src[i] = g_netRecvUsrInfo[rptr].src[i];
			}
		} else {
			pInfoMsg->flag = 1;
			pInfoMsg->src[0] = g_netRecvUsrInfo[rptr].src[0];
		}
		pInfoMsg->tsize = g_netRecvUsrInfo[rptr].tsize;
		rptr = (rptr + 1) & (RIO_RECV_LEVEL - 1);
		gxRecvUsrInfoRptr = rptr;
		gxRecvUsrInfoTotal++;
		return 1;
	}
	return 0;
}

void sync_xdma_drvrecv() 
{
	int res = 0;
	void *dstAddr = 0;
	unsigned int baseaddr;
	unsigned int base[6];
	unsigned int offset[6] = { 0, 0x28000000, 0x50000000, 0x80000000,
			0xa8000000, 0xd0000000 };
	unsigned int size;
	unsigned int fiberNum;
	unsigned int temp;
	unsigned int controlFlag;
	unsigned int bit_flag;
	unsigned int length_temp;
	int bianhao, lastbianhao;
	int fiberIndex[6];
	int i = 0;
	int fpga_fd = open("/dev/xdma0_c2h_0", O_RDWR | O_NONBLOCK);
	int bypass = open("/dev/xdma0_bypass", O_RDWR | O_SYNC);

	if (fpga_fd < 0 || bypass < 0) 
	{
		printf("Open device error! check your backup card or driver\n");
		return;
	}
	while (run_xdma_flag) 
	{
		memset(fiberIndex, 0, sizeof(fiberIndex));
		size = 0;
		baseaddr = 0;
		//read io pass
		res = reg_bypass_rw(bypass, 0);

		if (g_word != 0x0) {
			temp = g_word >> 61 & 0x7;
			if (temp == 7) {
//				printf("0x%016llx\n", g_word);
				fiberNum = (g_word >> 44) & 0x3f;

				xdma_tongbu = fiberNum;
				controlFlag = (g_word >> 60) & 0x1;
#if 1
				bianhao = (g_word >> 56) & 0xf;
				if (bianhao == 0) {
					lastbianhao = -1;
				}
				if (bianhao - lastbianhao != 1) {
					printf("error bianhao is %d lastbianhao is %d\n", bianhao,
							lastbianhao);
					lastbianhao = bianhao;
				} else {
					lastbianhao = bianhao;
				}
#endif
				if (controlFlag != 1) {
					for (i = 0; i < 6; i++) {
						if (((1 << i) & fiberNum) != 0) {
							fiberIndex[i] = 1;
						}
					}
					size = g_word & 0xffffffff;
					baseaddr = ((g_word >> 32) & 0xfff) << 20;
					g_netRecvUsrInfo[gxRecvUsrInfoWptr].pipeNum = fiberNum;
					g_netRecvUsrInfo[gxRecvUsrInfoWptr].flag = 0;

					for (i = 0; i < 6; i++) {
						if (fiberIndex[i] == 1) {
							base[i] = baseaddr + offset[i];
							dstAddr = (void*) xdmaMemAllocBuf(0, 4096, size);
							read_dma(fpga_fd, base[i], size, dstAddr);
							g_netRecvUsrInfo[gxRecvUsrInfoWptr].src[i] =dstAddr;
							g_netRecvUsrInfo[gxRecvUsrInfoWptr].tsize = size;
						}
					}
					gxRecvUsrInfoWptr = (gxRecvUsrInfoWptr + 1)& (RIO_RECV_LEVEL - 1);
					sem_post(&xdmaSemInput);
				} else {
					size = g_word & 0xffffffff;
					baseaddr = ((g_word >> 32) & 0xfff) << 20;
					g_netRecvUsrInfo[gxRecvUsrInfoWptr].pipeNum = 0x1000;
					g_netRecvUsrInfo[gxRecvUsrInfoWptr].flag = 1;
					dstAddr = (void*) xdmaMemAllocBuf(0, 4096, size);
					read_dma(fpga_fd, baseaddr, size, dstAddr);
					g_netRecvUsrInfo[gxRecvUsrInfoWptr].src[0] = dstAddr;
					g_netRecvUsrInfo[gxRecvUsrInfoWptr].tsize = size;
					gxRecvUsrInfoWptr = (gxRecvUsrInfoWptr + 1)& (RIO_RECV_LEVEL - 1);
					sem_post(&xdmaSemInput);
				}
			}
#if 1
			else {
				bit_flag = g_word >> 56 & 0xf;
				if (bit_flag == 0) {
					//printf("BIT 0x%016llx\n", g_word);
					for (i = 0; i < 6; i++) {
						xdma_fiberLength[i] = (g_word & 0xff) * 4;
						g_word = g_word >> 8;
					}
				} else if (bit_flag == 0xa) {
					xdma_fpga_version = g_word & 0xff;
				} else {
					xdma_k_count[bit_flag] = g_word & 0xffffffff;
				}
			}
#endif
		}
	}
	close(fpga_fd);
	close(bypass);
}

int sync_xdma_drvsend(void *srcAddr, unsigned int size, int flag) {
	unsigned int baseaddr = 0x1000;
	char diaodu[5000];
	char *pcXiankong;
	char *psrc;
	int count = 0;
	int qtx_count = 0;
	int last_count = 0;
	int qtx_last_count = 0;
	int total_size = 0;
	int i, j;
	int fpga_fd = open("/dev/xdma0_h2c_0", O_RDWR);
	if (fpga_fd < 0) 
	{
		return -1;
	}
//	if (flag == 1)
//	{
//		baseaddr = 0x8000000;
//		diaodu[0] = 0xab;
//		diaodu[1] = 0xab;
//		diaodu[2] = 0xcd;
//		diaodu[3] = 0xcd;
//		diaodu[4] = 0xef;
//		diaodu[5] = 0xef;
//		diaodu[6] = 0x5a;
//		diaodu[7] = 0x5a;
//		memcpy((char*) diaodu + 8, srcAddr, 2048);
//		diaodu[2056] = 0xab;
//		diaodu[2057] = 0xab;
//		diaodu[2058] = 0xcd;
//		diaodu[2059] = 0xcd;
//		diaodu[2060] = 0xef;
//		diaodu[2061] = 0xef;
//		diaodu[2062] = 0xa5;
//		diaodu[2063] = 0xa5;
//		write_dma(fpga_fd, baseaddr, 2064, (char*) diaodu);
//	}

	if(flag==1)
	{
		baseaddr = 0x8000000;
	}
	else
	{
		baseaddr = 0x1000;
	}
//	else
//	{
		pcXiankong = (char*) malloc(size + 32);

//		baseaddr = 0x1000;
		pcXiankong[0] = 0xab;
		pcXiankong[1] = 0xab;
		pcXiankong[2] = 0xcd;
		pcXiankong[3] = 0xcd;
		pcXiankong[4] = 0xef;
		pcXiankong[5] = 0xef;
		pcXiankong[6] = 0x5a;
		pcXiankong[7] = 0x5a;
		memcpy((char*) pcXiankong + 8, srcAddr, size);
		pcXiankong[size + 8] = 0xab;
		pcXiankong[size + 9] = 0xab;
		pcXiankong[size + 10] = 0xcd;
		pcXiankong[size + 11] = 0xcd;
		pcXiankong[size + 12] = 0xef;
		pcXiankong[size + 13] = 0xef;
		pcXiankong[size + 14] = 0xa5;
		pcXiankong[size + 15] = 0xa5;

		total_size = size + 16;
		qtx_count = total_size / 4096;
		for (j = 0; j < qtx_count; j++) 
		{
			for (i = 0; i < 2; i++) 
			{
				psrc = pcXiankong + i * 2048 + j * 4096;
				write_dma(fpga_fd, baseaddr, 2048, psrc);
			}
			usleep(5);
		}
		qtx_last_count = total_size % 4096;

		count = qtx_last_count / 2048;
		last_count = qtx_last_count % 2048;
		for (i = 0; i < count; i++) 
		{
			psrc = pcXiankong + i * 2048 + qtx_count * 4096;
			write_dma(fpga_fd, baseaddr, 2048, psrc);
		}
		psrc = pcXiankong + count * 2048 + qtx_count * 4096;
		write_dma(fpga_fd, baseaddr, last_count, psrc);
		free(pcXiankong);
//	}
	close(fpga_fd);
	return 0;
}
